package com.zhongkun.datahome.service.utils;

import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamUtil {

    public static <T> Stream<T> stream(List<T> list){
        if(list == null){
            return Stream.empty();
        }
        return list.stream();
    }

    public static <T, K, V> Map<K, V> listToMap(List<T> list, Function<T, K> getKey, Function<T, V> getValue) {

        if (CollectionUtils.isEmpty(list)) {
            return new HashMap<>();
        }
        Map<K, V> res = new HashMap<>();

        for (T t : list) {
            res.put(getKey.apply(t), getValue.apply(t));
        }

        return res;
    }

    public static <T, K> Map<K, List<T>> listGroupBy(List<T> list, Function<T, K> getKey) {

        if (CollectionUtils.isEmpty(list)) {
            return new HashMap<>();
        }

        return list.stream().filter(v -> getKey.apply(v) != null)
                .collect(Collectors.groupingBy(getKey));
    }

    public static <T, K, R> Map<K, R> listGroupByAndThen(Collection<T> list,
                                                         Function<T, Boolean> filter,
                                                         Function<T, K> getKey,
                                                         Function<List<T>, R> finish) {

        if (CollectionUtils.isEmpty(list)) {
            return new HashMap<>();
        }

        Map<K, List<T>> rm = list.stream().filter(v -> getKey.apply(v) != null && (filter == null || filter.apply(v)))
                .collect(Collectors.groupingBy(getKey));

        if (CollectionUtils.isEmpty(rm)) {
            return new HashMap<>();
        }

        Map<K, R> res = new HashMap<>();
        rm.forEach((k, l) -> res.put(k, finish.apply(l)));

        return res;
    }

    public static <T, K> Map<K, List<T>> listGroupByOrdered(List<T> list, Function<T, K> getKey, Comparator c) {

        if (CollectionUtils.isEmpty(list)) {
            return new HashMap<>();
        }

        Map<K, List<T>> res = new TreeMap<>(c);

        res.putAll(
                list.stream().filter(v -> getKey.apply(v) != null).collect(Collectors.groupingBy(getKey))
        );

        return res;
    }

    public static <T, K> Map<K, List<T>> listGroupByOrdered(List<T> list, Function<T, K> getKey) {

        return listGroupByOrdered(list, getKey, null);
    }

    public static <T> BigDecimal sum(List<T> list, Function<T, BigDecimal> getField) {
        if (CollectionUtils.isEmpty(list)) {
            return BigDecimal.ZERO;
        }

        return list.stream().map(getField).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    public static <T> BigDecimal sum(List<T> list, Function<T, BigDecimal> getField, Function<T, Boolean> filter) {
        if (CollectionUtils.isEmpty(list)) {
            return BigDecimal.ZERO;
        }

        return list.stream().filter(filter::apply).map(getField).reduce(BigDecimal.ZERO, BigDecimal::add);
    }

}
